package xyz.yuzegod.megawalls.game;

import net.minecraft.server.v1_8_R3.*;
import org.bukkit.Material;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
import org.bukkit.entity.Entity;
import org.bukkit.entity.*;
import org.bukkit.event.Event;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import xyz.yuzegod.megawalls.MegaWalls;
import xyz.yuzegod.megawalls.classes.Classes;
import xyz.yuzegod.megawalls.classes.ClassesManager;
import xyz.yuzegod.megawalls.effect.EffectManager;
import xyz.yuzegod.megawalls.effect.KillMessage;
import xyz.yuzegod.megawalls.event.PlayerEnergyChangeEvent;
import xyz.yuzegod.megawalls.event.PlayerKillEvent;
import xyz.yuzegod.megawalls.scoreboard.SidebarBoard;
import xyz.yuzegod.megawalls.spectator.SpectatorSettings;
import xyz.yuzegod.megawalls.spectator.SpectatorTarget;
import xyz.yuzegod.megawalls.stats.CurrencyPackage;
import xyz.yuzegod.megawalls.stats.EffectStatsContainer;
import xyz.yuzegod.megawalls.stats.KitStatsContainer;
import xyz.yuzegod.megawalls.stats.PlayerStats;
import xyz.yuzegod.megawalls.timer.ScoreBoardTimer;
import xyz.yuzegod.megawalls.util.ItemBuilder;
import xyz.yuzegod.megawalls.util.PlayerUtils;

import java.util.*;

public class GamePlayer
{
    private static final PotionEffect INVISIBILITY;
    private static final PotionEffect NIGHTVISION;
    private static final List<GamePlayer> gamePlayers;
    private final UUID uuid;
    private final String name;
    private final String displayName;
    private boolean isSpectator;
    private SpectatorTarget spectatorTarget;
    private GameTeam gameTeam;
    private boolean protect;
    private int kills;
    private int finalKills;
    private int protectChallenge;
    private PlayerStats playerStats;
    private List<Block> protectedBlock;
    private Inventory enderChest;
    private AssistsMap assistsMap;
    private int energy;
    private PlayerCompass playerCompass;
    
    public GamePlayer(final UUID uuid) {
        this.isSpectator = false;
        this.protect = false;
        this.kills = 0;
        this.finalKills = 0;
        this.protectChallenge = 0;
        this.protectedBlock = new ArrayList<Block>();
        this.enderChest = null;
        this.energy = 0;
        this.uuid = uuid;
        this.name = this.getPlayer().getName();
        this.displayName = ChatColor.stripColor(this.getPlayer().getDisplayName());
        this.assistsMap = new AssistsMap(this);
        this.playerStats = new PlayerStats(this);
        this.playerCompass = new PlayerCompass(this);
    }
    
    public static GamePlayer create(final UUID uuid) {
        GamePlayer gamePlayer = get(uuid);
        if (gamePlayer != null) {
            return gamePlayer;
        }
        gamePlayer = new GamePlayer(uuid);
        GamePlayer.gamePlayers.add(gamePlayer);
        return gamePlayer;
    }
    
    public static void remove(final UUID uuid) {
        if (get(uuid) != null) {
            GamePlayer.gamePlayers.remove(get(uuid));
        }
    }
    
    public static GamePlayer get(final UUID uuid) {
        for (final GamePlayer gamePlayer : GamePlayer.gamePlayers) {
            if (gamePlayer.getUuid().equals(uuid)) {
                return gamePlayer;
            }
        }
        return null;
    }
    
    public static List<GamePlayer> getGamePlayers() {
        return new ArrayList<GamePlayer>(GamePlayer.gamePlayers);
    }
    
    public static List<GamePlayer> getOnlinePlayers() {
        final List<GamePlayer> onlinePlayers = new ArrayList<GamePlayer>();
        for (final GamePlayer gamePlayer : GamePlayer.gamePlayers) {
            if (gamePlayer.isOnline()) {
                onlinePlayers.add(gamePlayer);
            }
        }
        return onlinePlayers;
    }
    
    public static List<GamePlayer> getSpectators() {
        final List<GamePlayer> spectators = new ArrayList<GamePlayer>();
        for (final GamePlayer gamePlayer : GamePlayer.gamePlayers) {
            if (gamePlayer.isSpectator()) {
                spectators.add(gamePlayer);
            }
        }
        return spectators;
    }
    
    public static List<GamePlayer> sortFinalKills() {
        final List<GamePlayer> list = new ArrayList<GamePlayer>(getOnlinePlayers());
        Collections.sort(list, new Comparator<GamePlayer>() {
            @Override
            public int compare(final GamePlayer player1, final GamePlayer player2) {
                return player2.getFinalKills() - player1.getFinalKills();
            }
        });
        return list;
    }
    
    public Player getPlayer() {
        return Bukkit.getPlayer(this.getUuid());
    }
    
    public String getDisplayName(final GamePlayer gamePlayer) {
        if (this.gameTeam != null && !this.isSpectator) {
            ChatColor chatColor = (gamePlayer == null) ? null : gamePlayer.getPlayerStats().getEffectStats().getColor(this.gameTeam.getTeamColor()).getChatColor();
            if (chatColor == null) {
                chatColor = this.gameTeam.getTeamColor().getChatColor();
            }
            return chatColor + this.displayName;
        }
        return "§9" + this.displayName;
    }
    
    public boolean isOnline() {
        return this.getPlayer() != null && this.getPlayer().isOnline();
    }
    
    public void sendActionBar(String message) {
        if (!this.isOnline()) {
            return;
        }
        message = ChatColor.translateAlternateColorCodes('&', message);
        final PlayerConnection connection = ((CraftPlayer)this.getPlayer()).getHandle().playerConnection;
        final IChatBaseComponent icbc = IChatBaseComponent.ChatSerializer.a("{\"text\": \"" + message + "\"}");
        final PacketPlayOutChat ppoc = new PacketPlayOutChat(icbc, (byte)2);
        connection.sendPacket((Packet)ppoc);
    }
    
    public void sendTitle(String title, String subTitle, final int fadeIn, final int stay, final int fadeOut) {
        if (!this.isOnline()) {
            return;
        }
        final PlayerConnection connection = ((CraftPlayer)this.getPlayer()).getHandle().playerConnection;
        if (title != null) {
            title = ChatColor.translateAlternateColorCodes('&', title);
            final IChatBaseComponent titleMain = IChatBaseComponent.ChatSerializer.a("{\"text\": \"" + title + "\"}");
            final PacketPlayOutTitle packetPlayOutTitle = new PacketPlayOutTitle(PacketPlayOutTitle.EnumTitleAction.TITLE, titleMain);
            connection.sendPacket((Packet)packetPlayOutTitle);
        }
        if (subTitle != null) {
            subTitle = ChatColor.translateAlternateColorCodes('&', subTitle);
            final IChatBaseComponent titleSub = IChatBaseComponent.ChatSerializer.a("{\"text\": \"" + subTitle + "\"}");
            final PacketPlayOutTitle packetPlayOutSubTitle = new PacketPlayOutTitle(PacketPlayOutTitle.EnumTitleAction.SUBTITLE, titleSub);
            connection.sendPacket((Packet)packetPlayOutSubTitle);
        }
    }
    
    public void sendMessage(String message) {
        if (!this.isOnline()) {
            return;
        }
        message = ChatColor.translateAlternateColorCodes('&', message);
        this.getPlayer().sendMessage(message);
    }
    
    public void playSound(final Sound sound, final float volume, final float pitch) {
        if (!this.isOnline()) {
            return;
        }
        this.getPlayer().playSound(this.getPlayer().getLocation(), sound, volume, pitch);
    }
    
    public void toSpectator(final String title, final String subTitle) {
        this.isSpectator = true;
        this.spectatorTarget = new SpectatorTarget(this, null);
        final Player player = this.getPlayer();
        if (player.isDead()) {
            PlayerUtils.respawn(player);
        }
        player.spigot().setCollidesWithEntities(false);
        player.setGameMode(GameMode.ADVENTURE);
        player.setFoodLevel(20);
        player.setMaxHealth(20.0);
        player.setHealth(20.0);
        player.setFireTicks(0);
        player.setLevel(0);
        player.setExp(0.0f);
        for (final Entity entity : player.getNearbyEntities(40.0, 40.0, 40.0)) {
            Creature livingEntity = null;
            if (entity instanceof Creature) {
                livingEntity = (Creature)entity;
                if (livingEntity.getTarget() == null || !livingEntity.getTarget().equals(this.getPlayer())) {
                    continue;
                }
                livingEntity.setTarget((LivingEntity)null);
            }
        }
        Bukkit.getScheduler().runTaskLater((Plugin)MegaWalls.getInstance(), (Runnable)new Runnable() {
            @Override
            public void run() {
                player.getInventory().setArmorContents((ItemStack[])null);
                player.getInventory().clear();
                player.getInventory().setItem(0, new ItemBuilder(Material.COMPASS).setDisplayName("§a§l传送器 §7(右键点击)").build());
                player.getInventory().setItem(4, new ItemBuilder(Material.DIODE).setDisplayName("§b§l旁观者设置 §7(右键点击)").build());
                player.getInventory().setItem(8, new ItemBuilder(Material.BED).setDisplayName("§c§l返回大厅 §7(右键点击)").build());
                for (final GamePlayer gamePlayer : GamePlayer.getSpectators()) {
                    if (!gamePlayer.isOnline()) {
                        return;
                    }
                    final Player player1 = gamePlayer.getPlayer();
                    final SidebarBoard b = SidebarBoard.of((Plugin)MegaWalls.getInstance(), player1);
                    player1.setScoreboard(b.getScoreboard());
                    ScoreBoardTimer.scoreboards.put(gamePlayer, b);
                    MegaWalls.getInstance().getGame().registerScoreboardTeams(player1);
                }
            }
        }, 15L);
        for (final PotionEffect effect : player.getActivePotionEffects()) {
            player.removePotionEffect(effect.getType());
        }
        player.addPotionEffect(GamePlayer.INVISIBILITY);
        final SpectatorSettings settings = SpectatorSettings.get(this);
        if (settings.getOption(SpectatorSettings.Option.NIGHTVISION)) {
            if (player.hasPotionEffect(PotionEffectType.NIGHT_VISION)) {
                player.removePotionEffect(PotionEffectType.NIGHT_VISION);
            }
            player.addPotionEffect(GamePlayer.NIGHTVISION);
        }
        player.setAllowFlight(true);
        player.setFlying(true);
        this.sendTitle(title, subTitle, 0, 100, 0);
        if (this.gameTeam != null && !this.gameTeam.getAlivePlayers().isEmpty()) {
            this.spectatorTarget.setTarget(this.gameTeam.getAlivePlayers().get(0));
        }
    }
    
    public void addKills() {
        ++this.kills;
    }
    
    public void addFinalKills() {
        ++this.finalKills;
    }

    
    public boolean isProtectedBlock(final Block block) {
        return this.protectedBlock.contains(block);
    }
    
    public void addProtectedBlock(final Block block) {
        this.protectedBlock.add(block);
    }
    
    public void removeProtectedBlock(final Block block) {
        this.protectedBlock.remove(block);
    }
    
    public void createEnderChest() {
        if (this.enderChest == null) {
            final int size = this.getPlayerStats().getKitStats(this.getPlayerStats().getSelected()).getEnderChest() * 9;
            this.enderChest = Bukkit.createInventory((InventoryHolder)this.getPlayer(), size, "末影箱");
        }
    }
    
    public void setLastDamage(final GamePlayer damager, final long time) {
        this.assistsMap.setLastDamage(damager, time);
    }
    
    public void handleKill(final GamePlayer gamePlayer, final Entity entity) {
        final GamePlayer self = this;
        final KillMessage killMessage = this.getPlayerStats().getEffectStats().getKillMessage();
        final EntityDamageEvent lastDamage = entity.getLastDamageCause();
        String reason = "被击杀";
        if (lastDamage != null) {
            if (lastDamage.getCause() == EntityDamageEvent.DamageCause.ENTITY_ATTACK) {
                reason = killMessage.getMessage("Attack");
            }
            else if (lastDamage.getCause() == EntityDamageEvent.DamageCause.POISON) {
                reason = killMessage.getMessage("Poison");
            }
            else if (lastDamage.getCause() == EntityDamageEvent.DamageCause.ENTITY_EXPLOSION || lastDamage.getCause() == EntityDamageEvent.DamageCause.BLOCK_EXPLOSION) {
                reason = killMessage.getMessage("Explode");
            }
            else if (lastDamage.getCause() == EntityDamageEvent.DamageCause.MAGIC) {
                reason = killMessage.getMessage("Magic");
            }
            else if (lastDamage instanceof EntityDamageByEntityEvent) {
                final EntityDamageByEntityEvent edbe = (EntityDamageByEntityEvent)lastDamage;
                if (edbe.getDamager() instanceof Projectile) {
                    final Projectile projectile = (Projectile)edbe.getDamager();
                    if (projectile instanceof Arrow) {
                        reason = killMessage.getMessage("Arrow");
                    }
                    else if (projectile instanceof Snowball) {
                        reason = killMessage.getMessage("Snowball");
                    }
                }
            }
        }
        final String finalReason = reason;
        getOnlinePlayers().forEach(viewer -> viewer.sendMessage(gamePlayer.getDisplayName(viewer) + " §f" + finalReason + ",击杀者: " + this.getDisplayName(viewer)));
        final Game game = MegaWalls.getInstance().getGame();
        Bukkit.getPluginManager().callEvent((Event)new PlayerKillEvent(game, this, gamePlayer));
        if (gamePlayer.getGameTeam().isWitherDead()) {
            EffectManager.generateHologram(this, gamePlayer, entity.getLocation());
            this.getPlayerStats().addFinalKills(1);
            this.getPlayerStats().giveCoins(new CurrencyPackage(15, "§b§l最终击杀"));
            Bukkit.getScheduler().runTaskLater((Plugin)MegaWalls.getInstance(), (Runnable)new Runnable() {
                @Override
                public void run() {
                    if (game.isProtected(entity.getLocation())) {
                        GamePlayer.this.getPlayerStats().giveCoins(new CurrencyPackage(9, "(防守奖励)"));
                    }
                    GamePlayer.this.addFinalKills();
                }
            }, 10L);
            final KitStatsContainer kitStats = this.getPlayerStats().getKitStats(this.getPlayerStats().getSelected());
            kitStats.addFinalKills(1);
            kitStats.giveMasterPoints(1);
            Bukkit.getScheduler().runTaskLater((Plugin)MegaWalls.getInstance(), (Runnable)new Runnable() {
                @Override
                public void run() {
                    for (final GamePlayer assistor : gamePlayer.getAssistsMap().getAssists(System.currentTimeMillis())) {
                        if (assistor.equals(self)) {
                            continue;
                        }
                        assistor.getPlayerStats().giveCoins(new CurrencyPackage(15, "§b§l最终击杀 §c§l助攻 §6击杀" + gamePlayer.getDisplayName(assistor)));
                        if (game.isProtected(entity.getLocation())) {
                            assistor.getPlayerStats().giveCoins(new CurrencyPackage(9, "(防守奖励)"));
                        }
                        assistor.addFinalKills();
                        final KitStatsContainer kitStats2 = assistor.getPlayerStats().getKitStats(assistor.getPlayerStats().getSelected());
                        kitStats2.giveMasterPoints(1);
                        kitStats2.addFinalAssists(1);
                    }
                }
            }, 20L);
            Bukkit.getScheduler().runTaskLater((Plugin)MegaWalls.getInstance(), (Runnable)new Runnable() {
                @Override
                public void run() {
                    gamePlayer.getPlayerStats().addGames();
                    final KitStatsContainer kitStats3 = gamePlayer.getPlayerStats().getKitStats(gamePlayer.getPlayerStats().getSelected());
                    kitStats3.addGames();
                    kitStats3.addPlayTime(System.currentTimeMillis() - MegaWalls.getInstance().getGame().getStartTime());
                }
            }, 30L);
        }
        else {
            this.getPlayerStats().addKills(1);
            this.getPlayerStats().giveCoins(new CurrencyPackage(4, null));
            Bukkit.getScheduler().runTaskLater((Plugin)MegaWalls.getInstance(), (Runnable)new Runnable() {
                @Override
                public void run() {
                    if (game.isProtected(entity.getLocation())) {
                        GamePlayer.this.getPlayerStats().giveCoins(new CurrencyPackage(9, "(防守奖励)"));
                    }
                    GamePlayer.this.addKills();
                }
            }, 10L);
            Bukkit.getScheduler().runTaskLater((Plugin)MegaWalls.getInstance(), (Runnable)new Runnable() {
                @Override
                public void run() {
                    for (final GamePlayer assistor : gamePlayer.getAssistsMap().getAssists(System.currentTimeMillis())) {
                        if (assistor.equals(self)) {
                            continue;
                        }
                        assistor.getPlayerStats().giveCoins(new CurrencyPackage(4, "§c§l助攻 §6击杀" + gamePlayer.getDisplayName(assistor)));
                        if (game.isProtected(entity.getLocation())) {
                            assistor.getPlayerStats().giveCoins(new CurrencyPackage(9, "(防守奖励)"));
                        }
                        assistor.addKills();
                    }
                }
            }, 30L);
        }
        if (game.getGameType() == GameType.NORMAL) {
            final Classes classes = ClassesManager.getSelected(this);
            if (this.getPlayerStats().getKitStats(classes).getLevel() >= 5) {
                this.getPlayerStats().giveCoins(new CurrencyPackage(1, "(精通IV " + classes.getDisplayName() + ")"));
            }
        }
    }
    
    public void addEnergy(final int energy, final PlayerEnergyChangeEvent.ChangeReason changeReason) {
        if (this.energy >= 100 || !this.isOnline()) {
            return;
        }
        final PlayerEnergyChangeEvent event = new PlayerEnergyChangeEvent(MegaWalls.getInstance().getGame(), this, changeReason, energy);
        Bukkit.getPluginManager().callEvent((Event)event);
        if (event.getAmount() > 0) {
            this.setEnergy(this.energy + event.getAmount());
        }
    }
    
    public void setEnergy(final int energy) {
        this.energy = energy;
        if (this.energy > 100) {
            this.energy = 100;
        }
        if (!this.isOnline()) {
            return;
        }
        this.getPlayer().setLevel(this.energy);
        this.getPlayer().setExp(this.energy / 100.0f);
    }
    
    public UUID getUuid() {
        return this.uuid;
    }
    
    public String getName() {
        return this.name;
    }
    
    public boolean isSpectator() {
        return this.isSpectator;
    }
    
    public SpectatorTarget getSpectatorTarget() {
        return this.spectatorTarget;
    }
    
    public void setSpectatorTarget(final SpectatorTarget spectatorTarget) {
        this.spectatorTarget = spectatorTarget;
    }
    
    public GameTeam getGameTeam() {
        return this.gameTeam;
    }
    
    public void setGameTeam(final GameTeam gameTeam) {
        this.gameTeam = gameTeam;
    }
    
    public boolean isProtect() {
        return this.protect;
    }
    
    public void setProtect(final boolean protect) {
        this.protect = protect;
    }
    
    public int getKills() {
        return this.kills;
    }
    
    public int getFinalKills() {
        return this.finalKills;
    }
    
    public int getProtectChallenge() {
        return this.protectChallenge;
    }
    
    public PlayerStats getPlayerStats() {
        return this.playerStats;
    }
    
    public List<Block> getProtectedBlock() {
        return this.protectedBlock;
    }
    
    public Inventory getEnderChest() {
        return this.enderChest;
    }
    
    public AssistsMap getAssistsMap() {
        return this.assistsMap;
    }
    
    public int getEnergy() {
        return this.energy;
    }
    
    public PlayerCompass getPlayerCompass() {
        return this.playerCompass;
    }
    
    static {
        INVISIBILITY = new PotionEffect(PotionEffectType.INVISIBILITY, Integer.MAX_VALUE, 1);
        NIGHTVISION = new PotionEffect(PotionEffectType.NIGHT_VISION, Integer.MAX_VALUE, 1);
        gamePlayers = new ArrayList<GamePlayer>();
    }
    
    public static class PlayerCompass
    {
        private static final List<GameTeam> teams;
        private GamePlayer gamePlayer;
        private Player player;
        private int index;
        
        public PlayerCompass(final GamePlayer gamePlayer) {
            this.index = 0;
            this.gamePlayer = gamePlayer;
            this.player = gamePlayer.getPlayer();
        }
        
        public void previous() {
            --this.index;
            if (this.index < 0) {
                this.index = PlayerCompass.teams.size() - 1;
            }
        }
        
        public void next() {
            ++this.index;
            if (this.index >= PlayerCompass.teams.size()) {
                this.index = 0;
            }
        }
        
        public void sendClosestPlayer() {
            final GameTeam gameTeam = PlayerCompass.teams.get(this.index);
            Player closest = null;
            for (final GamePlayer gamePlayer1 : gameTeam.getAlivePlayers()) {
                if (gamePlayer1.equals(this.gamePlayer)) {
                    continue;
                }
                final Player player1 = gamePlayer1.getPlayer();
                if (closest != null && player1.getLocation().distance(this.player.getLocation()) >= closest.getLocation().distance(this.player.getLocation())) {
                    continue;
                }
                closest = player1;
            }
            final EffectStatsContainer effectStats = this.gamePlayer.getPlayerStats().getEffectStats();
            final StringBuffer sb = new StringBuffer();
            if (closest != null) {
                final int distance = (int)closest.getLocation().distance(this.player.getLocation());
                sb.append("§f追踪: " + effectStats.getColor(gameTeam.getTeamColor()).getChatColor() + "§l" + gameTeam.getTeamColor().getText());
                sb.append(" §f- 最接近的玩家: " + effectStats.getColor(gameTeam.getTeamColor()).getChatColor() + distance + "§l米");
                this.player.setCompassTarget(closest.getLocation());
            }
            else {
                sb.append("§c§l没有");
                sb.append(effectStats.getColor(gameTeam.getTeamColor()).getChatColor() + "§l" + gameTeam.getTeamColor().getText() + "队");
                sb.append("§c§l玩家可供追踪！");
            }
            this.gamePlayer.sendActionBar(sb.toString());
        }
        
        public GamePlayer getGamePlayer() {
            return this.gamePlayer;
        }
        
        public Player getPlayer() {
            return this.player;
        }
        
        static {
            teams = new ArrayList<GameTeam>(MegaWalls.getInstance().getGame().getTeams());
        }
    }
}
